﻿using Microsoft.Azure;
using Microsoft.Cloud.API.Azure.Services;
using System.Threading.Tasks;
using System.Web.Http;
using Microsoft.WindowsAzure.Management.Compute.Models;
using Microsoft.WindowsAzure.Management.Storage.Models;
using Microsoft.Cloud.API.Azure.Models;
using Microsoft.Cloud.API.Azure.Common;

namespace Microsoft.Cloud.API.Azure.Controllers
{
    /// <summary>
    /// virtual machine controller
    /// </summary>
    [RoutePrefix("api/{subscriptionId}/VMs")]
    public class VMsController : ApiController
    {
        /// <summary>
        /// create a deployment and then a virtual machine in the deployment based on the specified configuration.
        /// </summary>
        /// <param name="subscriptionId"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        [Route("Deployment")]
        public async Task<IHttpActionResult> Post(string subscriptionId, VMDeploymentCreationModel model)
        {
            var computeService = new ComputeService(subscriptionId);
            var storageService = new StorageService(subscriptionId);
            try
            {
                #region cloud service
                var cloudServiceParameters = new HostedServiceCreateParameters
                {
                    ServiceName = model.CloudServiceName,
                    Label = model.CloudServiceName,
                    Location = model.Location,
                    //Description = "",
                    //AffinityGroup = vm.AffinityGroup,
                    //ReverseDnsFqdn = "",
                    //ExtendedProperties = null
                };

                var cloudServiceNameAvailabilityResponse = await computeService.CheckCloudServiceNameAsync(cloudServiceParameters.ServiceName);

                if (!cloudServiceNameAvailabilityResponse.IsAvailable)
                {
                    return BadRequest(cloudServiceNameAvailabilityResponse.Reason);
                }

                var cloudServiceOperationResponse = await computeService.CreateCloudServiceAsync(cloudServiceParameters);
                #endregion

                #region storage account
                var storageParameters = new StorageAccountCreateParameters
                {
                    Name = model.StorageAccountName,
                    Label = model.StorageAccountName,
                    AccountType = model.StorageAccountType,
                    Location = model.Location,
                    //Description = "",
                    //AffinityGroup = vm.AffinityGroup,
                    //ExtendedProperties = null
                };

                var storageNameAvailabilityResponse = await storageService.CheckStorageAccountNameAsync(storageParameters.Name);

                if (!storageNameAvailabilityResponse.IsAvailable)
                {
                    return BadRequest(storageNameAvailabilityResponse.Reason);
                }

                var storageOperationResponse = await storageService.CreateStorageAccountAsync(storageParameters);
                #endregion

                var vmOperationResponse = await computeService.CreateVMDeploymentAsync(model);

                return Ok(vmOperationResponse);
            }
            finally
            {
                if (computeService != null)
                {
                    computeService.Dispose();
                }
                if (storageService != null)
                {
                    storageService.Dispose();
                }
            }
        }

        /// <summary>
        /// get virtual machine disks
        /// </summary>
        /// <param name="subscriptionId"></param>
        /// <returns></returns>
        [Route("Disks")]
        public async Task<IHttpActionResult> GetDisks(string subscriptionId)
        {
            using (var computeService = new ComputeService(subscriptionId))
            {
                var result = await computeService.GetVMDiskListAsync();

                return Ok(result);
            }
        }

        /// <summary>
        /// add virtual machine
        /// </summary>
        /// <param name="subscriptionId"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IHttpActionResult> AddVM(string subscriptionId, VMCreationModel model)
        {
            var computeService = new ComputeService(subscriptionId); ;
            try
            {
                var vmOperationResponse = await computeService.CreateVMRoleAsync(model);

                return Ok(vmOperationResponse);
            }
            finally
            {
                if (computeService != null)
                {
                    computeService.Dispose();
                }
            }
        }

        /// <summary>
        /// shutdown, start, restart virtual machine
        /// </summary>
        ///// <param name="subscriptionId"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPut]
        public async Task<IHttpActionResult> OperationVM(string subscriptionId, VMOperationModel model)
        {
            var computeService = new ComputeService(subscriptionId); ;
            try
            {
                OperationStatusResponse vmOperationResponse = null;
                if (model.Operation == VMOperationModel.VMOperationAction.Shutdown)
                {
                    vmOperationResponse = await computeService.ShutdownVMRoleAsync(model);
                }
                else if (model.Operation == VMOperationModel.VMOperationAction.Start)
                {
                    vmOperationResponse = await computeService.StartVMRoleAsync(model);
                }
                else if (model.Operation == VMOperationModel.VMOperationAction.Restart)
                {
                    vmOperationResponse = await computeService.RestartVMRoleAsync(model);
                }
                else
                {
                    return BadRequest("please assign Operation parameter value correctly.");
                }

                return Ok(vmOperationResponse);
            }
            finally
            {
                if (computeService != null)
                {
                    computeService.Dispose();
                }
            }
        }

        /// <summary>
        /// get virtual machine
        /// </summary>
        /// <param name="subscriptionId"></param>
        /// <param name="cloudServiceName"></param>
        /// <param name="deploymentName"></param>
        /// <param name="vmName"></param>
        /// <returns></returns>
        [Route("{cloudServiceName}/{deploymentName}/{vmName}")]
        public async Task<IHttpActionResult> GetVM(string subscriptionId, string cloudServiceName, string deploymentName, string vmName)
        {
            var computeService = new ComputeService(subscriptionId); ;
            try
            {
                var response = await computeService.GetVMRoleAsync(cloudServiceName, deploymentName, vmName);

                return Ok(response);
            }
            finally
            {
                if (computeService != null)
                {
                    computeService.Dispose();
                }
            }
        }

        /// <summary>
        /// get virtual machine RDP
        /// </summary>
        /// <param name="subscriptionId"></param>
        /// <param name="cloudServiceName"></param>
        /// <param name="deploymentName"></param>
        /// <param name="vmName"></param>
        /// <returns></returns>
        [Route("{cloudServiceName}/{deploymentName}/{vmName}/RDP")]
        public async Task<IHttpActionResult> GetRDP(string subscriptionId, string cloudServiceName, string deploymentName, string vmName)
        {
            var computeService = new ComputeService(subscriptionId); ;
            try
            {
                var response = await computeService.GetRDPFileAsync(cloudServiceName, deploymentName, vmName);

                return new FileResult(vmName + ".rdp", response.RemoteDesktopFile);
            }
            finally
            {
                if (computeService != null)
                {
                    computeService.Dispose();
                }
            }
        }

        /// <summary>
        /// get os images
        /// </summary>
        /// <param name="subscriptionId"></param>
        /// <returns></returns>
        [Route("OSImages")]
        public async Task<IHttpActionResult> GetOSImages(string subscriptionId)
        {
            using (var computeService = new ComputeService(subscriptionId))
            {
                var result = await computeService.GetOSImagesListAsync();

                return Ok(result);
            }
        }
    }
}
